#include "Partitioner.hpp" 

using namespace std; 

/**
 * Partition chunk
 */ 
Partition::Partition(char *buffer, int len)
{
  string* p_str = new string(buffer, len); 
  this->strbuf = *p_str; 
}

Partition::Partition(string* str)
{
  this->strbuf = *str; 
}

string Partition::getBuffer()
{
  return this->strbuf; 
}

/**
 * Partitioner class
 */

Partitioner::Partitioner(list<string> files)
{
  this->files = files;
  this->f = NULL; 
  this->delim = " ";
  this->buffer = new char[chunkSize];
  this->openNextFile();
}  

Partitioner::~Partitioner()
{
  delete [] this->buffer; 
}

bool Partitioner::hasPartitions()
{
  return (this->files.size()> 0) || (this->f != NULL); 
}

Partition *Partitioner::getPartition()
{
  Partition* ret = NULL; 

  if (this->f != NULL)
    {
      int bytesr = fread(buffer, 1, chunkSize, this->f);
      if (bytesr == chunkSize)
	{
	  // move the file pointer to the first previous delimiter
	  string strbuf(buffer, chunkSize);
	  int rewind = - strbuf.rfind(this->delim) + strbuf.size() - this->delim.size(); 
	  if (0 != fseek(this->f, rewind, SEEK_CUR))
	    {
	      cerr << "fseek() failed \n";
	      return NULL; 
	    }
	  ret = new Partition(buffer, chunkSize - rewind); 
	}
      else
	{
	  // reached end of file 
	  ret = new Partition(new string(buffer, bytesr)); 
	  this->openNextFile(); 
	}
    }
  return ret;
}

void Partitioner::openNextFile()
{
  // previous opened file 
  if (this->f != NULL)
    fclose(this->f); 

  // try to open a file from the list 
  this->f = NULL; 
  while ((this->files.size() > 0) && (this->f == NULL))
    {
      string filename = this->files.front(); 
      this->files.pop_front(); 
      this->f = fopen(filename.c_str(), "rb");
      if (NULL == this->f)
	cerr << "IO Error opening " << filename << endl; 
    }
}
